/*
 * Copyright the original author or authors.
 * 
 * Licensed under the MOZILLA PUBLIC LICENSE, Version 1.1 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *	  http://www.mozilla.org/MPL/MPL-1.1.html
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.googlecode.milib.animation.dynamic_ {
	import com.googlecode.milib.base.MLActionClass;
	import com.googlecode.milib.service.ObjectEachPropertyOneChangerService;
	import com.googlecode.milib.service.singleton.EnterFrameService;
	import com.googlecode.milib.vo.MLEvent;

	public class AnimatedNumber extends MLActionClass {
		
		public const event_Update : String = 'Update';
		
		protected var efs:EnterFrameService;
		private var autoMappings :Array;
		private var targetValue:Number=0;
		private var currentValue:Number=0;
		private var initialValueSource:Array;
		public var isFinishWhenNoMapping:Boolean=false;
		private var countMappings:Number=0;
		private var autoUpdateTarget:Array;
		private var isCancel:Boolean;		public var isAutoMappingToInt:Boolean=false;		public var isAutoStart:Boolean=false;

		
		public function AnimatedNumber(initialCurrentValue:Number) {
			efs=EnterFrameService.getInstance();
			autoMappings=[];
			current=initialCurrentValue;
		}//<>
		/*abstract*/ protected function checkIsFinish():Boolean { return true; }
		/*abstract*/ protected function doEnterFrame():void { }		/*abstract*/ protected function doPrepare():void { }
		
		public function set target(num:Number):void {
			targetValue=num;
			if(isAutoStart){
				start();
			}
		}
		
		public function get target():Number {
			return targetValue;
		}
		
		public function set current(num:Number):void {
			if(currentValue==num){ return; }
			currentValue=num;
			countMappings=0;
			if(autoMappings){
				for(var i:uint=0,autoMapping:Array;i<autoMappings.length;i++){
					autoMapping=autoMappings[i];
					if(ObjectEachPropertyOneChangerService.forInstance(autoMapping[0]).setNewPropertyValue(this, autoMapping[1], isAutoMappingToInt ? Math.round(currentValue) : currentValue)){
						countMappings++;
					}
				}
			}
			if(checkIsFinish() || (isFinishWhenNoMapping && countMappings==0)) {
				finish();
			}
		}
		
		public function get current():Number {
			return currentValue;
		}
		
		override protected function doStart():Boolean {
			efs.addEventListener(efs.event_EnterFrame, onEnterFrame);
			if(autoUpdateTarget){ target=autoUpdateTarget[0][autoUpdateTarget[1]]; }
			doPrepare();
			for(var i:uint=0,autoMapping:Array;i<autoMappings.length;i++){
				autoMapping=autoMappings[i];
				ObjectEachPropertyOneChangerService.forInstance(autoMapping[0]).setNewChanger(this, autoMapping[1]);
			}
			if(initialValueSource) {
				currentValue=initialValueSource[0][initialValueSource[1]];
			}
			return true;
		}
		
		override protected function doFinish():Boolean {
			if(checkIsFinish() || (isFinishWhenNoMapping && countMappings==0) || isCancel){
				efs.removeEventListener(efs.event_EnterFrame, onEnterFrame);
				return true;
			}else{
				return false;
			}
		}
		
		public function cancel():void {
			isCancel=true;
			finish();
			isCancel=false;
		}
		
		public function setAutoUpdateTarget(obj:Object, propertyName:String):void {
			autoUpdateTarget=[obj, propertyName];
		}
		
		public function addAutoMapping(obj:Object, propertyName:String, isAlsoInitialSource:Boolean=false):void {
			if(!autoMappings){ autoMappings=[]; }
			autoMappings.push([obj, propertyName]);
			if(isAlsoInitialSource){
				setInitialValueSource(obj, propertyName);
			}else{
				obj[propertyName]=currentValue;
			}
		}
		
		public function setEnterFrameService(efs:EnterFrameService):void {
			if(getIsRunning()){
				this.efs.removeEventListener(efs.event_EnterFrame, onEnterFrame);
			}
			this.efs=efs;
			if(getIsRunning()){
				this.efs.addEventListener(efs.event_EnterFrame, onEnterFrame);
			}
		}
		
		public function setInitialValueSource(obj:Object, propertyName:String):void {
			initialValueSource=[obj, propertyName];
		}
		
//****************************************************************************
// EVENTS for AnimatedNumber
//****************************************************************************
		public function onEnterFrame(event:MLEvent):void {
			if(autoUpdateTarget){ target=autoUpdateTarget[0][autoUpdateTarget[1]]; }
			doEnterFrame();
			broadcastEvent(event_Update);
			finish();
		}
		
	}
}